
#import "WW3DHeightField.h"

#import "RIBTransformBegin.h"
#import "RIBScale.h"
#import "RIBSphere.h"
#import "RIBTransformEnd.h"
#import "WWSample.h"
#import "WWEveParser.h"
#import "WW3DAttributeState.h"

@implementation WW3DHeightField

+ initialize { return [WW3DHeightField setVersion:1], self; }

- init
{
  [super init];

  zScale = 1.0/255.;
  ribCommandList  = [[RIBCommandList alloc] init];
  dirtyBoundingBox = YES;
  
  return self;
}


- awake
{
    [super awake];
    dirtyBoundingBox = YES;
    return self;
}


- (BOOL)pushesOrPopsCTM { return NO; }
- (BOOL)pushesCTM { return NO; }
- (BOOL)popsCTM { return NO; }

- setZScale:(RtFloat)newZScale
{
   zScale = newZScale;
   return self;
}

- setImageName:(const char *)newImageName
     zScale:(float)newZScale
     n:(int)newN tokens:(RtToken *)newTokens parms:(RtPointer *)newParms archiveVector:(char **)newArchiveVector
     printfTypeVector:(int *)newPrintfTypeVector printfNVector:(int *)newPrintfNVector
{  
   id  sphereObj;


   image = nil;
   if (filename && *filename)
   { image = [NXImage findImageNamed:filename];
     if (!image) 
     {  image = [[NXImage alloc] init];
        [image setDataRetained:YES];
        if (![image loadFromFile:filename])
        {  NXLogError("unable to load image from file <%s>\n", filename);
           return nil; 
	 }
     }
   }


   [ribCommandList empty];

   sphereObj = [[RIBSphere alloc] init]; 
   [sphereObj setRadius:radius zMin:zMin zMax:zMax thetaMax:thetaMax
                    n:newN tokens:newTokens parms:newParms archiveVector:newArchiveVector printfTypeVector:newPrintfTypeVector printfNVector:newPrintfNVector];
   [sphereObj setMyShape:myShape];

   [ribCommandList insertObject:sphereObj at:0];
   [ribCommandList insertObject:[[[[RIBScale alloc] init] setSX:xScale sy:yScale sz:zScale] setMyShape:myShape] at:0];
   [ribCommandList insertObject:[[[RIBTransformBegin alloc] init] setMyShape:myShape] at:0];
   [ribCommandList addObject:[[[RIBTransformEnd alloc] init] setMyShape:myShape]];

   dirtyBoundingBox = TRUE;
  
   return self;
}

- setRadius:(RtFloat)newRadius { radius = newRadius; dirtyBoundingBox = TRUE; return self; }
- setZMin:(RtFloat)newZMin { zMin = newZMin; dirtyBoundingBox = TRUE; return self; }
- setZMax:(RtFloat)newZMax { zMax = newZMax; dirtyBoundingBox = TRUE; return self; }

- (RtFloat)radius { return radius; } 
- (RtFloat)zMin { return zMin; }
- (RtFloat)zMax { return zMax; }

- free
{
    [ribCommandList free];
    return [super free];
}

- (BOOL)hasBoundingBox		{ return YES; }
- (BOOL)isMotionBlurrable	{ return YES; }
- (BOOL)isCompoundCommand	{ return YES; }

- setBoundingBox:(RtBound *)newBoundingBox
{
    N3D_CopyBound(*newBoundingBox, boundingBox);
    return self;
}

- calculateBoundingBoxStartingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime  
{  
    dirtyBoundingBox = NO;
    return [self setBoundingBox:[ribCommandList boundingBoxStartingAt:shutterOpenTime endingAt:shutterCloseTime]];
}

- (RtBound *)boundingBoxStartingAt:(RtFloat)intervalStartTime endingAt:(RtFloat)intervalEndTime
{ 
   if (dirtyBoundingBox) 
   {  [self calculateBoundingBoxStartingAt:intervalStartTime endingAt:intervalEndTime];
   }
   return &boundingBox; 
}


- (float)lastSampleIsAt { return 0.0; }

- (unsigned long int)maxSampleBandwidth { return [ribCommandList maxSampleBandwidth]; }

- setMyShape:shape
{
    myShape = shape;
    return self;
}

- shape
{
    return myShape;
}

- renderMaps:(WW3DCamera *)camera
    startingAt:(RtFloat)shutterOpenTime
    endingAt:(RtFloat)shutterCloseTime usingStream:(NXStream *)ns
{
    return self;
}

- renderMaps:(WW3DCamera *)camera usingStream:(NXStream *)ns
{
    return self;
}

- renderMaps:(WW3DCamera *)camera
    startingAt:(RtFloat)shutterOpenTime
    endingAt:(RtFloat)shutterCloseTime
{
    return self;
}

- renderMaps:(WW3DCamera *)camera
{
    return self;
}

- renderSelfAsBox:(WW3DCamera *)camera
    startingAt:(RtFloat)shutterOpenTime
    endingAt:(RtFloat)shutterCloseTime
{
    return [ribCommandList renderSelfAsBox:camera
			   startingAt:shutterOpenTime
			   endingAt:shutterCloseTime];
}

- renderSelf:(WW3DCamera *)camera
    startingAt:(RtFloat)shutterOpenTime
    endingAt:(RtFloat)shutterCloseTime
{
    return [ribCommandList renderSelf:camera
			   startingAt:shutterOpenTime
			   endingAt:shutterCloseTime];
}

- renderSelf:(WW3DCamera *)camera
{
    return [ribCommandList renderSelf:camera];
}

- preRenderSelf:(WW3DCamera *)camera
    startingAt:(RtFloat)shutterOpenTime
    endingAt:(RtFloat)shutterCloseTime
{
    return [ribCommandList preRenderSelf:camera
			   startingAt:shutterOpenTime
			   endingAt:shutterCloseTime];
}

- preRenderSelf:(WW3DCamera *)camera
{
    return [ribCommandList preRenderSelf:camera];
}

- transformCTM:(WW3DAttributeState *)attributeState
    startingAt:(RtFloat)shutterOpenTime
    endingAt:(RtFloat)shutterCloseTime 
{
    return [ribCommandList transformCTM:attributeState
                           startingAt:shutterOpenTime
			   endingAt:shutterCloseTime]; 
}

// methods to make me look like a compound command:
- (int)count {  return [ribCommandList count]; }
- objectAt:(int)i {  return [ribCommandList objectAt:i]; }


// WavesWorld archiving:
// writeEve:(NXStream *)stream
// writeScene:(NXStream *)stream

- writeEve:(NXStream *)stream atTabLevel:(int)tab
{
    int  i;
    
    for (i = 0; i < tab; i++) {
	NXPrintf(stream, "\t");
    }
    NXPrintf(stream, "WW3DHeightField %s %f ", imageName, zScale);
    return self;
}

- writeScene:(NXStream *)stream atTabLevel:(int)tab
{
  return [self writeEve:stream atTabLevel:tab];
}

#define typeVector "*@f"
#define typeValues &imageName, &image, &zScale

- read:(NXTypedStream *)stream 
{
    int version;
    
    [super read:stream];
    version = NXTypedStreamClassVersion(stream,"WW3DHeightField");
    if (version == 0) NXReadTypes(stream, "i", &version), version = 1;
    if (version == 1)
    {  NXReadTypes(stream, typeVector, typeValues);
       NXReadArray(stream, "f", 6, boundingBox);
       myShape = NXReadObject(stream);
    }

    return self;
}

- write:(NXTypedStream *)stream 
{
    [super write:stream];
    NXWriteTypes(stream, typeVector, typeValues);
    NXWriteArray(stream, "f", 6, boundingBox);
    NXWriteObjectReference(stream, myShape);
    return self;
}

- (BOOL)theSameAs:otherRIBCommand
{
  // WAVE: really should try and return YES, but for now...
  return NO;
}

- (BOOL)isMoot
{
  return NO;
}

// boy, this is dumb... This is to get around the stupid warnings from the compiler - ask wave for details
- class { return [super class]; }



@end
